#ifndef TCPCONNECTION_H
#define TCPCONNECTION_H

#include <functional>
#include <memory>

#include "Noncopyable.h"
#include "Channel.h"
#include "Socket.h"
#include "InetAddress.h"
#include "callbacks.h"
#include "Buffer.h"

class StringPiece;


class TcpConnection: Noncopyable,
                    public std::enable_shared_from_this<TcpConnection> {
public:
    enum State {
        connecting,
        connected,
        disconnecting,
        disconnected
    };

    TcpConnection(EventLoop* loop, int connFd, 
            const InetAddress& serverAddr, const InetAddress& peerAddr);
    ~TcpConnection();

    void send(const char* str, size_t len);
    void send(const StringPiece& str);

    void shutdown();  // 关闭写，只剩读，进入半连接状态

    void forceClose();  // 主动关闭连接

    void setConnectionCallback(const ConnectionCallback& cb) {
        connectionCallback_ = std::move(cb);
    }
    void setMessageCallback(const MessageCallback& cb) {
        messageCallback_ = std::move(cb);    
    }
    void setCloseCallback(const CloseCallback& cb) {
        closeCallback_ = std::move(cb);
    }
    void setWriteCompleteCallback(const WriteCompleteCallback& cb) {
        writeCompleteCallback_ = std::move(cb);
    }
    void setHighWaterMarkCallback(const HighWaterMarkCallback& cb, const size_t highWaterMark) {
        highWaterMarkCallback_ = std::move(cb);
        highWaterMark_ = highWaterMark;
    }

    bool isConnected() { return state_ == connected; }

    void connectEstablished();
    void connectDestroyed();

private:
    void sendInLoop(const char* str, size_t len);

    void shutdownInLoop();

    void forceCloseInLoop();

    void handleRead();
    void handleWrite();
    void handleClose();

    EventLoop* loop_;
    Socket connSocket_;
    Channel channel_;
    InetAddress serverAddr_;
    InetAddress peerAddr_;
    State state_;
    size_t highWaterMark_;

    Buffer inputBuf_;
    Buffer outputBuf_;

    ConnectionCallback connectionCallback_;
    MessageCallback messageCallback_;
    CloseCallback closeCallback_;
    WriteCompleteCallback writeCompleteCallback_;
    HighWaterMarkCallback highWaterMarkCallback_;

};

#endif